home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / JMenuBar.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  19.4 KB  |  690 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)JMenuBar.java    1.52 98/04/09
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package javax.swing;
  16.  
  17. import java.awt.Component;
  18. import java.awt.Dimension;
  19. import java.awt.Graphics;
  20. import java.awt.Insets;
  21. import java.awt.Point;
  22. import java.awt.Rectangle;
  23. import java.awt.event.*;
  24. import java.util.Vector;
  25. import java.util.Enumeration;
  26.  
  27. import java.io.Serializable;
  28. import java.io.ObjectOutputStream;
  29. import java.io.ObjectInputStream;
  30. import java.io.IOException;
  31.  
  32. import javax.swing.event.*;
  33. import javax.swing.border.Border;
  34. import javax.swing.plaf.*;
  35. import javax.accessibility.*;
  36.  
  37. /**
  38.  * An implementation of a MenuBar. You add JMenu objects to the
  39.  * menu bar to construct a menu. When the user selects a JMenu
  40.  * object, its associated JPopupMenu is displayed, allowing the
  41.  * user to select one of the JMenuItems on it.
  42.  * <p>
  43.  * For the keyboard keys used by this component in the standard Look and
  44.  * Feel (L&F) renditions, see the
  45.  * <a href="doc-files/Key-Index.html#JMenuBar">JMenuBar</a> key assignments.
  46.  * <p>
  47.  * <strong>Warning:</strong>
  48.  * Serialized objects of this class will not be compatible with 
  49.  * future Swing releases.  The current serialization support is appropriate
  50.  * for short term storage or RMI between applications running the same
  51.  * version of Swing.  A future release of Swing will provide support for
  52.  * long term persistence.
  53.  *
  54.  * @version 1.52 04/09/98
  55.  * @author Georges Saab
  56.  * @author David Karlton
  57.  * @author Arnaud Weber
  58.  * @see JMenu
  59.  * @see JPopupMenu
  60.  * @see JMenuItem
  61.  */
  62. public class JMenuBar extends JComponent implements Accessible,MenuElement
  63. {    
  64.     /**
  65.      * @see #getUIClassID
  66.      * @see #readObject
  67.      */
  68.     private static final String uiClassID = "MenuBarUI";
  69.  
  70.     /*
  71.      * Model for the selected subcontrol
  72.      */
  73.     private transient SingleSelectionModel selectionModel;
  74.  
  75.     private boolean paintBorder           = true;
  76.     private Insets     margin             = null;
  77.  
  78.     /**
  79.      * Creates a new menu bar.
  80.      */
  81.     public JMenuBar() {
  82.         super();
  83.         setSelectionModel(new DefaultSingleSelectionModel());
  84.         updateUI();
  85.     }
  86.  
  87.     /**
  88.      * Returns the menubar's current UI.
  89.      * @see #setUI
  90.      */
  91.     public MenuBarUI getUI() {
  92.         return (MenuBarUI)ui;
  93.     }
  94.     
  95.     /**
  96.      * Sets the L&F object that renders this component.
  97.      *
  98.      * @param ui the new MenuBarUI L&F object
  99.      * @see UIDefaults#getUI
  100.      */
  101.     public void setUI(MenuBarUI ui) {
  102.         super.setUI(ui);
  103.     }
  104.     
  105.     /**
  106.      * Notification from the UIFactory that the L&F has changed. 
  107.      * Called to replace the UI with the latest version from the 
  108.      * UIFactory.
  109.      *
  110.      * @see JComponent#updateUI
  111.      */
  112.     public void updateUI() {
  113.         setUI((MenuBarUI)UIManager.getUI(this));
  114.     }
  115.  
  116.  
  117.     /**
  118.      * Returns the name of the L&F class that renders this component.
  119.      *
  120.      * @return "MenuBarUI"
  121.      * @see JComponent#getUIClassID
  122.      * @see UIDefaults#getUI
  123.      */
  124.     public String getUIClassID() {
  125.         return uiClassID;
  126.     }
  127.  
  128.  
  129.     /**
  130.      * Returns the model object that handles single selections.
  131.      *
  132.      * @return the SingleSelectionModel in use
  133.      * @see SingleSelectionModel
  134.      */
  135.     public SingleSelectionModel getSelectionModel() {
  136.         return selectionModel;
  137.     }
  138.  
  139.     /**
  140.      * Set the model object to handle single selections.
  141.      *
  142.      * @param model the SingleSelectionModel to use
  143.      * @see SingleSelectionModel
  144.      */
  145.     public void setSelectionModel(SingleSelectionModel model) {
  146.         final JMenuBar thisMenuBar = this;
  147.         selectionModel = model;
  148.     }
  149.  
  150.  
  151.     /**
  152.      * Appends the specified menu to the end of the menu bar.
  153.      *
  154.      * @param c the JMenu component to add
  155.      */
  156.     public JMenu add(JMenu c) {
  157.         super.add(c);
  158.         return c;
  159.     }
  160.  
  161.     /**
  162.      * Gets the menu at the specified position in the menu bar.
  163.      *
  164.      * @param index  an int giving the position in the menu bar, where
  165.      *               0 is the first position
  166.      * @return the JMenu at that position
  167.      */
  168.     public JMenu getMenu(int index) {
  169.         Component c = getComponentAtIndex(index);
  170.         if (c instanceof JMenu) 
  171.             return (JMenu) c;
  172.         return null;
  173.     }
  174.  
  175.     /**
  176.      * Returns the number of items in the menu bar.
  177.      *
  178.      * @return the number of items in the menu bar
  179.      */
  180.     public int getMenuCount() {
  181.         return getComponentCount();
  182.     }
  183.  
  184.     /**
  185.      * Sets the help menu that appears when the user selects the
  186.      * "help" option in the menu bar. This method is not yet implemented.
  187.      *
  188.      * @param menu the JMenu that delivers help to the user
  189.      */
  190.     public void setHelpMenu(JMenu menu) {
  191.         throw new Error("setHelpMenu() not yet implemented.");
  192.     }
  193.  
  194.     /**
  195.      * Gets the help menu for the menu bar.
  196.      *
  197.      * @return the JMenu that delivers help to the user
  198.      */
  199.     public JMenu getHelpMenu() {
  200.         throw new Error("getHelpMenu() not yet implemented.");
  201.     }
  202.  
  203.     /**
  204.      * Returns the component at the specified index.
  205.      *
  206.      * @param i an int specifying the position, where 0 = first
  207.      * @return the Component at the position, or null for an
  208.      *         invalid index
  209.      */
  210.     public Component getComponentAtIndex(int i) {
  211.     int ncomponents = this.getComponentCount();
  212.     if (i>=0 && i < ncomponents) {
  213.         Component[] component = this.getComponents();
  214.         return component[i];
  215.     }
  216.     return null;
  217.     }
  218.  
  219.     /**
  220.      * Returns the index of the specified component.
  221.      *
  222.      * @param c  the Component to find
  223.      * @return an int giving the component's position, where 0 = first
  224.      */
  225.     public int getComponentIndex(Component c) {
  226.         int ncomponents = this.getComponentCount();
  227.         Component[] component = this.getComponents();
  228.         for (int i = 0 ; i < ncomponents ; i++) {
  229.             Component comp = component[i];
  230.             if (comp == c) 
  231.                 return i;
  232.         }
  233.         return -1;
  234.     }
  235.  
  236.     /**
  237.      * Sets the currently selected component, producing a
  238.      * a change to the selection model.
  239.      *
  240.      * @param sel the Component to select
  241.      */
  242.     public void setSelected(Component sel) {    
  243.         SingleSelectionModel model = getSelectionModel();
  244.         int index = getComponentIndex(sel);
  245.         model.setSelectedIndex(index);
  246.     }
  247.  
  248.     /**
  249.      * Returns true if the MenuBar currently has a component selected
  250.      *
  251.      * @return true if a selection has been made, else false
  252.      */
  253.     public boolean isSelected() {       
  254.         return selectionModel.isSelected();
  255.     }
  256.  
  257.     /** 
  258.      * Returns true if a the Menubar's border should be painted.
  259.      *
  260.      * @return  true if the border should be painted, else false
  261.      */
  262.     public boolean isBorderPainted() {
  263.         return paintBorder;
  264.     }
  265.  
  266.     /** 
  267.      * Determines whether the MenuBar's current border will be painted.
  268.      *
  269.      * @param s  true if the border should be painted, else false
  270.      */
  271.     public void setBorderPainted(boolean s) {
  272.         paintBorder = s;
  273.     }
  274.  
  275.     /**
  276.      * Paint the menubar's border if BorderPainted property is true.
  277.      * 
  278.      * @param g the Graphics context to use for painting
  279.      * @see JComponent#paint
  280.      * @see JComponent#setBorder
  281.      */
  282.     protected void paintBorder(Graphics g) {    
  283.         if (isBorderPainted()) {
  284.             super.paintBorder(g);
  285.         }
  286.     }
  287.  
  288.     /**
  289.      * Sets the margin between the menubar's border and
  290.      * its menus. Setting to null will cause the menubar to
  291.      * use the default margins.
  292.      *
  293.      * @param margin an Insets object containing the margin values
  294.      * @see Insets
  295.      */
  296.     public void setMargin(Insets margin) {
  297.         this.margin = margin;
  298.         invalidate();
  299.     }
  300.  
  301.     /**
  302.      * Returns the margin between the menubar's border and
  303.      * its menus.
  304.      * 
  305.      * @return an Insets object containing the margin values
  306.      * @see Insets
  307.      */
  308.     public Insets getMargin() {
  309.         if(margin == null) {
  310.             return new Insets(0,0,0,0);
  311.         } else {
  312.             return margin;
  313.         }
  314.     }
  315.  
  316.  
  317.     /**
  318.      * Implemented to be a MenuElement -- does nothing. 
  319.      *
  320.      * @see #getSubElements
  321.      */
  322.     public void processMouseEvent(MouseEvent event,MenuElement path[],MenuSelectionManager manager) {
  323.     }
  324.  
  325.     /**
  326.      * Implemented to be a MenuElement -- does nothing.
  327.      *
  328.      * @see #getSubElements
  329.      */
  330.     public void processKeyEvent(KeyEvent e,MenuElement path[],MenuSelectionManager manager) {
  331.     }
  332.  
  333.     /** 
  334.      * Implemented to be a MenuElement -- does nothing.
  335.      *
  336.      * @see #getSubElements
  337.      */
  338.     public void menuSelectionChanged(boolean isIncluded) {
  339.     }
  340.     
  341.     /** 
  342.      * Implemented to be a MenuElement -- returns the menus in this menu 
  343.      * bar. This is the reason for implementing the MenuElement
  344.      * interface -- so that the menu bar can be treated the same as
  345.      * other menu elements.
  346.      */
  347.     public MenuElement[] getSubElements() {
  348.         int menuCount = getMenuCount();
  349.         int i;
  350.         MenuElement result[] = new MenuElement[menuCount];
  351.         for(i=0;i<menuCount;i++)
  352.             result[i] = getMenu(i);
  353.         return result;
  354.     }
  355.     
  356.     /** 
  357.      * Implemented to be a MenuElement. Returns this object. 
  358.      *
  359.      * @return the current Component (this)
  360.      * @see #getSubElements
  361.      */
  362.     public Component getComponent() {
  363.         return this;
  364.     }
  365.  
  366.  
  367.     /**
  368.      * Returns a string representation of this JMenuBar. This method 
  369.      * is intended to be used only for debugging purposes, and the 
  370.      * content and format of the returned string may vary between      
  371.      * implementations. The returned string may be empty but may not 
  372.      * be <code>null</code>.
  373.      * <P>
  374.      * Overriding paramString() to provide information about the
  375.      * specific new aspects of the JFC components.
  376.      * 
  377.      * @return  a string representation of this JMenuBar.
  378.      */
  379.     protected String paramString() {
  380.     String paintBorderString = (paintBorder ?
  381.                     "true" : "false");
  382.     String marginString = (margin != null ?
  383.                    margin.toString() : "");
  384.  
  385.     return super.paramString() +
  386.     ",margin=" + marginString +
  387.     ",paintBorder=" + paintBorderString;
  388.     }
  389.  
  390. /////////////////
  391. // Accessibility support
  392. ////////////////
  393.  
  394.     /**
  395.      * Get the AccessibleContext associated with this JComponent
  396.      *
  397.      * @return the AccessibleContext of this JComponent
  398.      */
  399.     public AccessibleContext getAccessibleContext() {
  400.         if (accessibleContext == null) {
  401.             accessibleContext = new AccessibleJMenuBar();
  402.         }
  403.         return accessibleContext;
  404.     }
  405.  
  406.     /**
  407.      * The class used to obtain the accessible role for this object.
  408.      * <p>
  409.      * <strong>Warning:</strong>
  410.      * Serialized objects of this class will not be compatible with
  411.      * future Swing releases.  The current serialization support is appropriate
  412.      * for short term storage or RMI between applications running the same
  413.      * version of Swing.  A future release of Swing will provide support for
  414.      * long term persistence.
  415.      */
  416.     protected class AccessibleJMenuBar extends AccessibleJComponent 
  417.         implements AccessibleSelection {
  418.  
  419.         /**
  420.          * Get the accessible state set of this object.
  421.          *
  422.          * @return an instance of AccessibleState containing the current state 
  423.          *         of the object
  424.          */
  425.         public AccessibleStateSet getAccessibleStateSet() {
  426.             AccessibleStateSet states = super.getAccessibleStateSet();
  427.             return states;
  428.         }
  429.  
  430.         /**
  431.          * Get the role of this object.
  432.          *
  433.          * @return an instance of AccessibleRole describing the role of the 
  434.          * object
  435.          */
  436.         public AccessibleRole getAccessibleRole() {
  437.             return AccessibleRole.MENU_BAR;
  438.         }
  439.  
  440.         /**
  441.          * Get the AccessibleSelection associated with this object if one
  442.          * exists.  Otherwise return null.
  443.          */
  444.         public AccessibleSelection getAccessibleSelection() {
  445.             return this;
  446.         }
  447.  
  448.         /**
  449.          * Returns 1 if a menu is currently selected in this menu bar.
  450.          *
  451.          * @return 1 if a menu is currently selected, else 0
  452.          */
  453.          public int getAccessibleSelectionCount() {
  454.             if (isSelected()) {
  455.                 return 1;
  456.             } else {
  457.                 return 0;
  458.             }
  459.          }
  460.     
  461.         /**
  462.          * Returns the currently selected menu if one is selected, 
  463.          * otherwise null.
  464.          */
  465.          public Accessible getAccessibleSelection(int i) {
  466.             if (isSelected()) {
  467.         if (i != 0) {    // single selection model for JMenuBar
  468.             return null;
  469.         }
  470.                 int j = getSelectionModel().getSelectedIndex();
  471.                 if (getComponentAtIndex(j) instanceof Accessible) {
  472.                     return (Accessible) getComponentAtIndex(j);
  473.                 }           
  474.             }
  475.             return null;
  476.          }
  477.  
  478.         /**
  479.          * Returns true if the current child of this object is selected.
  480.          *
  481.          * @param i the zero-based index of the child in this Accessible 
  482.          * object.
  483.          * @see AccessibleContext#getAccessibleChild
  484.          */
  485.         public boolean isAccessibleChildSelected(int i) {
  486.             return (i == getSelectionModel().getSelectedIndex());
  487.         }
  488.  
  489.         /**
  490.          * Selects the nth menu in the menu bar, forcing it to
  491.      * pop up.  If another menu is popped up, this will force
  492.      * it to close.  If the nth menu is already selected, this 
  493.      * method has no effect.
  494.          *
  495.          * @param i the zero-based index of selectable items
  496.          * @see #getAccessibleStateSet
  497.          */
  498.         public void addAccessibleSelection(int i) {
  499.         // first close up any open menu
  500.             int j = getSelectionModel().getSelectedIndex();
  501.         if (i == j) {
  502.         return;
  503.         }
  504.         if (j >= 0 && j < getMenuCount()) {
  505.                 JMenu menu = getMenu(j);
  506.                 if (menu != null) {
  507.             MenuSelectionManager.defaultManager().setSelectedPath(null);
  508. //            menu.setPopupMenuVisible(false);
  509.                 }
  510.         }
  511.         // now popup the new menu
  512.             getSelectionModel().setSelectedIndex(i);
  513.         JMenu menu = getMenu(i);
  514.         if (menu != null) {
  515.         MenuElement me[] = new MenuElement[3];
  516.         me[0] = JMenuBar.this;
  517.         me[1] = menu;
  518.         me[2] = menu.getPopupMenu();
  519.         MenuSelectionManager.defaultManager().setSelectedPath(me);
  520. //        menu.setPopupMenuVisible(true);
  521.         }
  522.         }
  523.     
  524.         /**
  525.          * Removes the nth selected item in the object from the object's
  526.          * selection.  If the nth item isn't currently selected, this
  527.          * method has no effect.  Otherwise, it closes the popup menu.
  528.          *
  529.          * @param i the zero-based index of selectable items
  530.          */
  531.         public void removeAccessibleSelection(int i) {
  532.         if (i >= 0 && i < getMenuCount()) {
  533.         JMenu menu = getMenu(i);
  534.         if (menu != null) {
  535.             MenuSelectionManager.defaultManager().setSelectedPath(null);
  536. //            menu.setPopupMenuVisible(false);
  537.         }
  538.         getSelectionModel().setSelectedIndex(-1);
  539.         }
  540.         }
  541.     
  542.         /**
  543.          * Clears the selection in the object, so that nothing in the
  544.          * object is selected.  This will close any open menu.
  545.          */
  546.         public void clearAccessibleSelection() {
  547.         int i = getSelectionModel().getSelectedIndex();
  548.         if (i >= 0 && i < getMenuCount()) {
  549.         JMenu menu = getMenu(i);
  550.         if (menu != null) {
  551.             MenuSelectionManager.defaultManager().setSelectedPath(null);
  552. //            menu.setPopupMenuVisible(false);
  553.         }
  554.         }
  555.             getSelectionModel().setSelectedIndex(-1);
  556.         }
  557.  
  558.         /**
  559.          * Normally causes every selected item in the object to be selected
  560.          * if the object supports multiple selections.  This method
  561.      * makes no sense in a menu bar, and so does nothing.
  562.          */
  563.         public void selectAllAccessibleSelection() {
  564.         } 
  565.     } // internal class AccessibleJMenuBar
  566.  
  567.  
  568.     /**
  569.      * Returns true to indicate that this component manages focus
  570.      * events internally.
  571.      *
  572.      * @return true
  573.      */
  574.     public boolean isManagingFocus() {
  575.         return true;
  576.     }
  577.  
  578.     KeyboardBinding bindingForKeyStroke(KeyStroke ks,int condition) {
  579.         // Does it exist for the MenuBar?
  580.         KeyboardBinding kbb =  super.bindingForKeyStroke(ks, condition);
  581.         if (kbb != null)
  582.             return kbb;
  583.  
  584.         int i;
  585.         Component subComponents[];
  586.  
  587.         subComponents = getComponents();
  588.         for(i=0 ; i < subComponents.length ; i++) {
  589.             // If 
  590.             if(subComponents[i] instanceof JMenu) {
  591.                 kbb = bindingForKeyStrokeRecursive(subComponents[i], ks, condition);
  592.             }
  593.             if (kbb != null)
  594.                 return kbb;
  595.         }       
  596.         return null;
  597.     }
  598.  
  599.     static KeyboardBinding bindingForKeyStrokeRecursive(Component c,
  600.                                                         KeyStroke ks,int condition) {
  601.         KeyboardBinding kbb = null;
  602.  
  603.         if (c==null)
  604.             return null;
  605.  
  606.         if (c instanceof JComponent) {
  607.             kbb = ((JComponent)c).bindingForKeyStroke(ks, condition);       
  608.             if (kbb != null)
  609.                 return kbb;
  610.         }
  611.  
  612.         if (c instanceof JMenu) {
  613.             JMenu m = (JMenu)c;
  614.             int i;
  615.             Component subComponents[];
  616.             
  617.             subComponents = m.getMenuComponents();
  618.         if (subComponents != null) {
  619.         for(i=0 ; i < subComponents.length ; i++) {
  620.             if(subComponents[i] instanceof JMenuItem) {
  621.             kbb = bindingForKeyStrokeRecursive(subComponents[i], 
  622.                                ks, condition);
  623.             }               
  624.             if (kbb != null)
  625.             return kbb;
  626.         }
  627.         }
  628.         }
  629.         return kbb;
  630.     }
  631.  
  632.     /**
  633.      * Overrides <code>JComponent.addNotify</code> to register this
  634.      * menu bar with the current {@link KeyboardManager}.
  635.      */
  636.     public void addNotify() {
  637.         super.addNotify();
  638.     KeyboardManager.getCurrentManager().registerMenuBar(this);
  639.     }
  640.  
  641.     /**
  642.      * Overrides <code>JComponent.removeNotify</code> to unregister this
  643.      * menu bar with the current {@link KeyboardManager}.
  644.      */
  645.     public void removeNotify() {
  646.         super.removeNotify();
  647.     KeyboardManager.getCurrentManager().unregisterMenuBar(this);
  648.     }
  649.  
  650.  
  651.     private void writeObject(ObjectOutputStream s) throws IOException {
  652.         s.defaultWriteObject();
  653.  
  654.         Object[] kvData = new Object[4];
  655.         int n = 0;
  656.  
  657.         if (selectionModel instanceof Serializable) {
  658.             kvData[n++] = "selectionModel";
  659.             kvData[n++] = selectionModel;
  660.         }
  661.  
  662.         s.writeObject(kvData);
  663.     }
  664.  
  665.  
  666.     /**
  667.      * See JComponent.readObject() for information about serialization
  668.      * in Swing.
  669.      */
  670.     private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException 
  671.     {
  672.         s.defaultReadObject();
  673.         Object[] kvData = (Object[])(s.readObject());
  674.  
  675.         for(int i = 0; i < kvData.length; i += 2) {
  676.             if (kvData[i] == null) {
  677.                 break;
  678.             }
  679.             else if (kvData[i].equals("selectionModel")) {
  680.                 selectionModel = (SingleSelectionModel)kvData[i + 1];
  681.             }
  682.         }
  683.  
  684.     if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  685.         ui.installUI(this);
  686.     }
  687.     }
  688. }
  689.  
  690.